using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

public class GUIScoreMeter : MonoBehaviour {
	
	private bool endGameDisplay = false;
	private bool display = true;
	
	//Positions & Layout
	public float meterSize = 70;
	public float meterPosition = 20;
	public float movementSpeed = 1;				// How fast all 
	
	private float crownSize 		= 75;		// Size of the crown texture
	public float rightMargin	 	= 50;		// Distance from Scoreboard to 
	private float GUIWidth			= 350;		// Width of GUI-Group
	private float hatSize			= 75;		// Size of the hat textures
	private float hatDistance		= 50;		// Distance from hats to scoremeter
	
	//Test Variables
	public bool debug = false;
	private Score currentPlayer;
	private Texture2D testSquare;

	//Textures
	public Texture2D crownTexture;
	public Texture2D scoreMeterTexture;
	public Texture2D scoreDividerTexture;
	public Texture2D[] hatTextures;
	private int id = -1;
	
	private struct Score{
		public int player;
		public int score;
		public float displayPos;
		public float newPos;
		
		public Score(int player,int score){
			this.player = player;
			this.score = score;
			this.displayPos = 0;
			this.newPos = 0;
		}
	}

	private List<Score> playerScores = new List<Score>();
	
	void Awake(){
	// Check if textures are missing
		foreach (FieldInfo fi in this.GetType().GetFields()){
			if (fi.FieldType == typeof(Texture2D)){
				if (fi.GetValue(this).ToString() == "null"){
					Texture2D newTexture = new Texture2D(100,100);
					newTexture.Apply();
					fi.SetValue(this,newTexture);
					if (fi.Name != "testSquare")
						Debug.LogWarning("Texture " + fi.Name + " in " + this.GetType() + " in gameojbect " + this.name + " is missing.");
				}
			}
		}	
	}
	
	void Start () {	
		ScoreListener.inst().add(delegate(ScoreEvent ev) {
			switch (ev.getAction()) {
				case ScoreAction.ADD: 	 addPlayer(ev.getPlayerID(),ev.getScore()); 	break;
				case ScoreAction.UPDATE: updateScore(ev.getPlayerID(), ev.getScore()); 	break;
				case ScoreAction.REMOVE: removePlayer(ev.getPlayerID()); 				break;
			}
		});
		
	}
	
	private void addPlayer(int player,int score) {
		playerScores.Add(new Score(player,score));
	}
	
	private void updateScore(int player, int score) {
		Debug.Log("Player: "+player+" Scored!");
		for (int i = 0;i<playerScores.Count;i++) {
			if (playerScores[i].player == player) {
				Score temp = playerScores[i];
				temp.score += score;
				playerScores[i] = temp;
				break;
			}
		}
		//Debug.LogWarning("Trying to update score for unknown player");
	}
	
	private void removePlayer(int player) {
		foreach(Score sc in playerScores){
			if(sc.player == player){playerScores.Remove(sc);
				break;
			}
		}
		Debug.LogWarning("Trying to remove unknown player");		
	}
	
	void OnGUI(){
		
		if (endGameDisplay){
			rightMargin 	= Mathf.Lerp(rightMargin,(50),Time.deltaTime/movementSpeed);
			meterSize 		= Mathf.Lerp(meterSize,82,Time.deltaTime/movementSpeed);
			meterPosition 	= Mathf.Lerp(meterPosition,0,Time.deltaTime/movementSpeed);
			GUIWidth  		= Screen.width;
			GUI.Label(new Rect(0,0,Screen.width,Screen.height)," ","box");
			GUI.Label(new Rect(0,0,Screen.width,Screen.height)," ","box");
			GUI.Label(new Rect(0,0,Screen.width,Screen.height)," ","box");
			GUI.Label(new Rect(0,0,Screen.width,Screen.height)," ","box");
			GUI.Label(new Rect(0,0,Screen.width,Screen.height)," ","box");
			Screen.showCursor = true;
			if (gameObject.GetComponent<GUIHealthBar>() != null){
				gameObject.GetComponent<GUIHealthBar>().enabled = false;
			}
			if (gameObject.GetComponent<PlayerGUI>() != null){
				gameObject.GetComponent<PlayerGUI>().enabled = false;
			}
		}
		
		GUI.BeginGroup(new Rect(Screen.width-GUIWidth,
								((Screen.height-(Screen.height*meterSize/100))/2)+Screen.height*meterPosition/100,
								GUIWidth,
								(Screen.height*meterSize/100)));
		
			// Displays size of GUI-Group
			if (debug){
				if (testSquare == null){
					testSquare = new Texture2D(1,1);
					testSquare.Apply();
				}
				GUI.DrawTexture(new Rect(0,0,Screen.width,Screen.height),testSquare,ScaleMode.StretchToFill);
			}
			
			// How much to scale some objects in width
			float widthScale = Mathf.Clamp(((Screen.height*meterSize/100)*meterSize/100),0,scoreMeterTexture.height)/scoreMeterTexture.height;
			
			// Crown Texture
			GUI.DrawTexture(new Rect(	GUIWidth-(Screen.width*rightMargin/100)-(crownSize*widthScale)/2,
										((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2-(crownSize*widthScale),
										(crownSize*widthScale),
										(crownSize*widthScale)),
										crownTexture,
										ScaleMode.ScaleToFit);
			
			
			// Score Meter Texture
			GUI.DrawTexture(new Rect(	GUIWidth-(Screen.width*rightMargin/100)-18,
										(((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2),
										36,
										((Screen.height*meterSize/100)*meterSize/100)),
										scoreMeterTexture,
										ScaleMode.ScaleToFit);
			
			// Bottom of the Score Meter
			float end 	 = ((Screen.height*meterSize/100)*meterSize/100)+(((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2);	
			// Length of the Score Meter
			float length = ((Screen.height*meterSize/100)*meterSize/100);
			
			//Divider Texture
			GUI.DrawTexture(new Rect(	GUIWidth-(Screen.width*rightMargin/100)-scoreDividerTexture.width*widthScale/2,
										end - length * 0.3f + scoreDividerTexture.height,
										scoreDividerTexture.width*widthScale, 
										scoreDividerTexture.height),
										scoreDividerTexture,
										ScaleMode.ScaleToFit);
			
			
			if(playerScores.Count>0){
				playerScores.Sort((s1,s2) => s1.score.CompareTo(s2.score));
				
				float min = playerScores[0].score;
				float max = playerScores[playerScores.Count-1].score;
				
				// Loop Through Players
				foreach (Score player in playerScores) {
					
					Score tempPlayer = player;
					
					if (player.score > max - 10) {
						tempPlayer.newPos = (length * 0.3f) + ((length * 0.7f) / 9) * (player.score - (max - 9)) - (((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2);
					} else {
						tempPlayer.newPos = ((length * 0.3f) / ((max - 9) - min)) * (player.score - min) - (((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2);
					}
					
					tempPlayer.displayPos = Mathf.Lerp(tempPlayer.displayPos,tempPlayer.newPos,Time.deltaTime/movementSpeed);
	
					for(int i = 0; i < playerScores.Count; i++){
						if (playerScores[i].player == tempPlayer.player)
							playerScores[i] = tempPlayer;
					}
					
					float xHatPosition = GUIWidth-(Screen.width*rightMargin/100)-(crownSize*widthScale)/2-(hatSize*widthScale)/2-(hatDistance*widthScale);
					
					if (player.player == id) {
						GUI.DrawTexture(new Rect(xHatPosition, end - tempPlayer.displayPos-(hatSize*widthScale)/2-(((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2), (hatSize*widthScale), (hatSize*widthScale)), hatTextures[0]);
					} else {
						GUI.DrawTexture(new Rect(xHatPosition, end - tempPlayer.displayPos-(hatSize*widthScale)/2-(((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2), (hatSize*widthScale), (hatSize*widthScale)), hatTextures[1]);
					}
					if (debug)
						GUI.Label(new Rect(xHatPosition-135,end-tempPlayer.displayPos-(hatSize*widthScale)/2-(((Screen.height*meterSize/100)-((Screen.height*meterSize/100)*meterSize/100))/2),125,25),"ID: " + player.player + " SCORE: " + player.score,"box");
				}
			}	
		GUI.EndGroup();
		
		// Testing GUI
		if (debug){
			if (GUI.Button(new Rect(Screen.width/2-100,Screen.height-100,200,25),"Add Player","box"))
				addPlayer(getNumberOfPlayers(),0);
			if (playerScores.Count > 0) {
				int currentPosition = -1;
				for(int i = 0; i < playerScores.Count; i++){
					if (currentPlayer.player==playerScores[i].player){
						currentPlayer = playerScores[i];
						currentPosition = i;	
					}
				}
				GUI.Label(new Rect(Screen.width/2-100,Screen.height-75,200,25),"The Score of player " + currentPlayer.player + " = " + currentPlayer.score + ". [" + (currentPosition+1) + "/" + getNumberOfPlayers() + "]","box");	
				if (GUI.Button(new Rect(Screen.width/2+100,Screen.height-75,50,25),"+","box"))
					updateScore(currentPlayer.player,1);
				if (GUI.Button(new Rect(Screen.width/2-150,Screen.height-75,50,25),"-","box"))
					if (currentPlayer.score > 0)
						updateScore(currentPlayer.player,-1);
				if (GUI.Button(new Rect(Screen.width/2+100,Screen.height-50,50,25),"+","box"))
					if (currentPosition < playerScores.Count-1)
						currentPlayer = playerScores[currentPosition+1];
				if (GUI.Button(new Rect(Screen.width/2-150,Screen.height-50,50,25),"-","box"))
					if (currentPosition > 0)
						currentPlayer = playerScores[currentPosition-1];
				if (GUI.Button(new Rect(Screen.width/2-100,Screen.height-50,200,25),"End Game","box"))
					endGame();
			}
		}
	}
	
	public int getNumberOfPlayers(){
		return playerScores.Count;	
	}
	
	void Update(){
		if(id ==-1){
			setID ();
		}
	}
	
	public void setID(){
		WeaponSystem[] weapons = Object.FindObjectsOfType(typeof(WeaponSystem)) as WeaponSystem[];
		foreach(WeaponSystem w in weapons){
			if( w.enabled ){
				id = w.gameObject.GetComponent<NID>().getId();
			}
		}
	}
	
	public void endGame(){
		endGameDisplay = true;
	}
	
	public bool isWinner(){
		int id = -1;
		int highest = -1;
		foreach(Score s in playerScores){
			if(s.score>highest){
				highest = s.score;
				id = s.player;
			}
		}
		if(id == this.id)
			return true;
		else
			return false;
	}
}
